package com.hzit.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.hzit.common.utils.MyDate;
import com.hzit.seckill.entity.SeckillStatus;
import com.hzit.seckill.entity.TbSeckillGoods;
import com.hzit.seckill.interceptor.LoginInteceptor;
import com.hzit.seckill.service.MultiThreadingCreateOrder;
import com.hzit.seckill.service.SeckillOrderService;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.ReactiveSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 类名：
 * 作者：WF
 * 功能：
 */
@Service
public class SeckillOrderServiceImpl implements SeckillOrderService {

	@Autowired
	private StringRedisTemplate redisTemplate;
	@Autowired
	private MultiThreadingCreateOrder createOrder;
	@Autowired
	private RedissonClient redissonClient;

	//1. 保存订单
	@Override
	public void saveOrder(String id) {
		String name = LoginInteceptor.loginUserName.get();
		//1.1 构造订单状态对象
		Date date = MyDate.getDateMenus().get(0);
		String time = MyDate.getDateStr(date);
		SeckillStatus seckillStatus = new SeckillStatus(name,new Date(),1,new Long(id),time);


		//1.2 避免重复排队
		//1.2.1 自增1
		Long userQueueCount = redisTemplate.boundHashOps("UserQueueCount").increment(name, 1);
		//1.2.2 如果返回值大于1，说明重复排队
		if(userQueueCount > 1){
			throw new RuntimeException("对不起，不能重复排队！");
		}
		//1.3 为了公平性起见，先排队的先购买，可以将上面的seckillStatus放到redis的list左边
		redisTemplate.boundListOps("SeckillOrderQueue").leftPush(JSON.toJSONString(seckillStatus));
		//1.4 为了避免将来删除seckillStatus对象，我们可以在redis中将其备份一份
		redisTemplate.opsForValue().set("seckillStatus",JSON.toJSONString(seckillStatus));

		Long secKillId = seckillStatus.getSecKillId();
		BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps("seckillGoods_" + seckillStatus.getTime());
		String s = operations.get(secKillId + "");
		TbSeckillGoods seckillGoods = JSON.parseObject(s, TbSeckillGoods.class);

		//放一个信号量到redis加
		RSemaphore semaphore = redissonClient.getSemaphore("seckill:semaphore:" + id);
		//根据库存量设置信号量
		semaphore.trySetPermits(seckillGoods.getStockCount());
		//1.5 异步下单
		createOrder.fareOrder();

	}
}
